﻿using System;

using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using DirectUI.Mobile.UI;

namespace DirectUI.Mobile.UI.Controls
{
    /// <summary>
    /// Shows only one control sized with it's own size and supports animated navigation from one
    /// control to another.
    /// </summary>
    /// <example>
    /// This control usually contains ListBoxes and/or panels to enable an animted switching to another control.
    /// </example>
    public class PageManagerDic : DirectUIControl,IContainer
    {


        //public IEnumerable<DirectUIControl> Controls { get {
      
        //} }
        public override void Scale(SizeF scaleFactor)
        {
            base.Scale(scaleFactor);
            foreach (IPage page in this.Pages.Values)
            {
                page.Scale(scaleFactor);
            }
        }
        /// <summary>
        /// the control that is currently transitioning.
        /// </summary>
        private IPage transitionControl;
        public PageCollectionDic Pages;
        const int animDuration = 405;
        public void Switch(string name, Transition tran)
        {
            Switch(name, tran, animDuration);
        }
        public void GoBack()
        {
            if (!string.IsNullOrEmpty(this.SelectedPage.PrevPage))
            {
                this.Switch(this.SelectedPage.PrevPage, Transition.ShiftLeft);
            }
        }
        protected override void InitControl()
        {
            base.InitControl();
            BackColor = Color.Empty;
            Pages = new PageCollectionDic(this);
            Pages.ControlAdded += new EventHandler<ControlEventArgs>(Pages_ControlAdded);
        }

        void Pages_ControlAdded(object sender, ControlEventArgs e)
        {
            ControlAdded(e.Control);
        }

        public override void Dispose()
        {
            if (dbuffer != null) dbuffer.Dispose();
            foreach(IPage p in Pages.Values){
                if (p != null)
                {
                    p.Dispose();
                }
            }
            base.Dispose();
        }
        public System.Drawing.Point PointToHost(int x, int y)
        {

            return Host.PointToHost(x + Left, y + Top);

        }
        Rectangle IContainer.GetScreenBounds(Rectangle bounds)
        {
            bounds.Offset(Left, Top);
        //    if (Container != null)
         //   {
                return Container.GetScreenBounds(bounds);
          //  }
          
            //else
            //{
            //    return  Host.GetScreenBounds(bounds);
            //}
        }
        public virtual void Invalidate(Rectangle bounds)
        {
            if (dbuffer != null) dbuffer.Invalidate(bounds);
            if (!Visible) return;
            if (Initializing) return;
            if (Container == null ) return;

            bounds.Offset(Left, Top);
            // don't let the child control invalidate anything outside the own bounds:
            ClipRectangle(ref bounds);
            if (Container != null)
            {
                Container.Invalidate(bounds);
            }
            else
            {
                Host.Invalidate(bounds);
            }
        }
     
        public IHost Host
        {
            get
            {
                //if (this.host != null)
                //{
                //    return this.host;
                //}
                return Container != null ? this.Container.Host : null;
            }
        }
        #region INotifyControlAdded Members

        private void ControlAdded(IDirectUIControl control)
        {
            if (control.Width == 0 || control.Height == 0||this.ScaleFactor.Width==1f)
            {
                control.Bounds = this.ClientRectangle;
            }
            if (Pages.Count == 1)
            {
                SelectedPageName = control.Name;
            }
            control.Visible = SelectedPage == control;

        }

        #endregion

        private string selectedPageName = "";
        public string SelectedPageName
        {
            get
            {
                return selectedPageName;
            }
            set
            {
                if (!CheckPageNameExist(value))
                {
                    return;
                }
                if (selectedPageName != value)
                {
                    //  OnSelectedIndexChanging(selectedPageName, value);
                    if (!string.IsNullOrEmpty(selectedPageName))
                    {
                        IPage old = SelectedPage;
                        old.Visible = false;
                    }
                    selectedPageName = value;
                    IPage c = SelectedPage;
                    BeginInit();
                 //   SelectedPage.Bounds = ClientRectangle;
                    if (c != null)
                    {
                        c.Bounds = ClientRectangle;
                        c.OnEnter(this.Host);
                        c.Visible = true;
                    }

                 
                    EndInit();
                    Invalidate();

                }
            }
        }


        private ChangedEventArgs<int> indexChangeEventArgs = new ChangedEventArgs<int>();

        //protected virtual void OnSelectedIndexChanging(int currentIndex, int newIndex)
        //{

        //    if (SelectedIndexChanging != null)
        //    {
        //        indexChangeEventArgs.OldValue = currentIndex;
        //        indexChangeEventArgs.NewValue = newIndex;
        //        SelectedIndexChanging(this, indexChangeEventArgs);
        //    }
        //    if (currentIndex != -1)
        //    {
        //        this.Pages[currentIndex].OnLeave(this.Host);
        //    }
        //    this.Pages[newIndex].OnEnter(this.Host);
        //}



        private DoubleBuffer dbuffer;

  


        /// <summary>
        /// Gets the selected control otherwhise null.
        /// </summary>
        public IPage SelectedPage
        {
            get
            {
                return Pages[selectedPageName];
            }

        }

        private bool CheckPageNameExist(string name)
        {
            return Pages.Contains(name);
        }

        protected override void OnSizeChanged(System.Drawing.Size oldSize, System.Drawing.Size newSize)
        {
            base.OnSizeChanged(oldSize, newSize);
            if (transitionControl != null) transitionControl.Bounds = ClientRectangle;
            if (!string.IsNullOrEmpty(selectedPageName)) SelectedPage.Bounds = ClientRectangle;
        }

        protected override void OnPaintBackground(DirectUIPaintEventArgs e)
        {
            // dont use background painting
        }

        //public override void OnPaint(DirectUIPaintEventArgs e)
        //{
        //    if (!IsInTransiton)
        //    {
        //        DirectUIControl c = SelectedPage;
        //        if (c != null) c.OnPaint(e);
        //    }
        //    else base.OnPaint(e);
        //}
        public override void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
        {
            if (this.SelectedPage != null)
            {
                this.SelectedPage.OnKeyDown(e);
            }
        }
        public override void OnMove(PointEventArgs p)
        {
            if (this.SelectedPage != null)
            {
                this.SelectedPage.OnMove(p);
            }
        }
        public override bool OnClick(PointEventArgs p)
        {
            if (this.SelectedPage != null)
            {
                return this.SelectedPage.OnClick(p);
            }
            return false;
        }
        public override void OnDown(PointEventArgs p)
        {
            if (this.SelectedPage != null)
            {
                this.SelectedPage.OnDown(p);
            }
        }
        public override void OnUp(PointEventArgs p)
        {
            if (this.SelectedPage != null)
            {
                this.SelectedPage.OnUp(p);
            }
        }
        public override void OnGesture(GestureEventArgs e)
        {
            if (this.SelectedPage != null)
            {
                this.SelectedPage.OnGesture(e);
            }
        }
        private Animation animation;

        Animation EnsureAnimation()
        {
            if (animation == null)
            {
                animation = new Animation();
                animation.Scene += new EventHandler<AnimationEventArgs>(animation_Scene);
                animation.Started += new EventHandler(animation_Started);
                //animation.Mode = AnimationMode.Log;
                //animation.Acceleration = 0.05f;
                animation.Mode = AnimationMode.Accelerated;
                animation.Acceleration = -3.3f;
                animation.Completed += new EventHandler(animation_Completed);
            }
            return animation;
        }

        /// <summary>
        /// Update after the animation has completed the first scene, to ensure no delay while rendering and caching the new tab 
        /// for the very first time:
        /// </summary>
        void animation_Started(object sender, EventArgs e)
        {
            Update();
        }

        void animation_Completed(object sender, EventArgs e)
        {
            transitionControl.Bounds = ClientRectangle;
            SelectedPageName = transitionControl.Name;
            transitionControl = null;
            currentTransition = Transition.None;
            dBufferRequired = false;
            OnTransitionCompleted(sender as Animation);
        }

        private int alpha;

        #region Transitions
        private TranistionFunc transitionFunc;

        delegate void TranistionFunc(int value);

        void Fade(int value)
        {
            alpha = 2 * 255 * value / animation.EndValue;
            Rectangle r1 = ClientRectangle;
            SelectedPage.Bounds = r1;
            transitionControl.Bounds = r1;
            Invalidate();
        }

        void MoveLeft(int value)
        {
            BeginInit();
            Rectangle r1 = ClientRectangle;
            Rectangle r2 = ClientRectangle;

            r2.X = r1.Right - value;
            SelectedPage.Bounds = r1;
            transitionControl.Bounds = r2;
            transitionControl.Visible = true;
            EndInit();
            Invalidate();
        }

        void MoveRight(int value)
        {
            BeginInit();
            Rectangle r1 = ClientRectangle;
            Rectangle r2 = ClientRectangle;

            r2.X = value - r2.Width;
            SelectedPage.Bounds = r1;
            transitionControl.Bounds = r2;
            transitionControl.Visible = true;
            EndInit();
            Invalidate();
        }


        DoubleBuffer ensureDBuffer()
        {
            if (dbuffer == null) dbuffer = new DoubleBuffer();
            return dbuffer;
        }


        /// <summary>
        /// TabPanel uses this flag to switch of double buffering, since TabPanel implements it's own buffering.
        /// </summary>
        internal bool InternalEnableDoubleBuffer = true;

        public override void OnPaint(DirectUIPaintEventArgs e)
        {
            if (InternalEnableDoubleBuffer && dBufferRequired)
            {
                DoubleBuffer buffer = ensureDBuffer();
                buffer.Paint(e, this, this.PaintPages, alpha);
            }
            else PaintPages(e);
        }

        protected  void PaintPages(DirectUIPaintEventArgs pe)
        {
            base.OnPaint(pe);
            IPage c = SelectedPage;
            IPage tc = transitionControl;

    
            if (c != null) PaintControl(pe, c);

            if (tc != null) PaintControl(pe, tc);
        }

        protected  Rectangle PaintControl(DirectUIPaintEventArgs pe, IDirectUIControl c)
        {
            Rectangle controlBounds = pe.ControlBounds;
            Region clip = pe.Region;
            Rectangle bounds = c.Bounds;
            bounds.Offset(controlBounds.X, controlBounds.Y);
            if (clip.IsVisible(bounds))
            {
                PaintControlUnbuffered(pe, c, bounds);
            }
            return bounds;
        }
        private DirectUIPaintEventArgs paintEventArgs = new DirectUIPaintEventArgs();

        protected void PaintControlUnbuffered(DirectUIPaintEventArgs pe, IDirectUIControl control, Rectangle bounds)
        {
            DirectUIPaintEventArgs e = paintEventArgs;
            e.Graphics = pe.Graphics;
            e.ControlBounds = bounds;
            e.Region = pe.Region;
            e.ScaleFactor = pe.ScaleFactor;
            control.OnPaint(e);
        }
        void ShiftLeft(int value)
        {
            BeginInit();
            Rectangle r1 = ClientRectangle;
            Rectangle r2 = ClientRectangle;

            r1.X -= value;
            r2.X = r1.Right;
            SelectedPage.Bounds = r1;
            if (transitionControl != null)
            {
                transitionControl.Bounds = r2;
                transitionControl.Visible = true;
            }
            EndInit();
            Invalidate();
        }
        public override void Invalidate()
        {
            if (Initializing || !Visible) return;
            if (Container != null) Container.Invalidate(this.Bounds);
            if (InternalEnableDoubleBuffer && dBufferRequired) ensureDBuffer().Invalidate();
        }
        void ShiftRight(int value)
        {
            BeginInit();
            Rectangle r1 = ClientRectangle;
            Rectangle r2 = ClientRectangle;

            r1.X += value;
            r2.X = r1.Left - r2.Width;
            //r2.X += value;
            //r1.X = 0;
            SelectedPage.Bounds = r1;
            transitionControl.Bounds = r2;
            transitionControl.Visible = true;
            EndInit();
            Invalidate();
        }

        void None(int value) { }

        TranistionFunc GetTransitionFunc(Transition transition)
        {
            switch (transition)
            {
                case Transition.ShiftLeft: return ShiftLeft;
                case Transition.ShiftRight: return ShiftRight;
                case Transition.MoveLeft: return MoveLeft;
                case Transition.MoveRight: return MoveRight;
                case Transition.Fade: return Fade;

                default: throw new NotSupportedException(transition.ToString());
            }
        }

        public bool RequiresDBuffer(Transition transaction)
        {
            switch (currentTransition)
            {

                case Transition.ShiftRight:
                case Transition.ShiftLeft:
                case Transition.ShiftTop:
                case Transition.ShiftBottom:
                case Transition.None:
                    return false;
                default:
                    return true;
            }
        }

        bool dBufferRequired = false;

        public bool IsInTransiton { get { return transitionControl != null; } }

        private Transition currentTransition = Transition.None;


        void animation_Scene(object sender, AnimationEventArgs e)
        {

            int value = Width * e.Value / e.EndValue;
            if (transitionControl == null)
            {
                DirectUI.Common.Log.Instance.Debug("transitionControl is null,animation_Scene fail");
                return;
            }
            else if(SelectedPage == null)           
            {
                DirectUI.Common.Log.Instance.Debug("SelectedPage is null,animation_Scene fail");
                return;
            }
            transitionFunc(value);
            OnTransitionChange(e);
        }

        protected virtual void OnTransitionChange(AnimationEventArgs e)
        {
            if (TransitionChange != null) TransitionChange(this, e);
        }

        protected virtual void OnTransitionCompleted(Animation a)
        {
            if (TransitionCompleted != null)
            {
                TransitionCompleted(this, a.eventArgs);
            }
            this.SelectedPage.Left = 0;
            this.SelectedPage.Top = 0;
        }

        public event EventHandler<AnimationEventArgs> TransitionChange;
        public event EventHandler<AnimationEventArgs> TransitionCompleted;

        public void Switch(string name, Transition transition, int duration)
        {
            StopTransition();
            if (name != selectedPageName)
            {

                alpha = 255;
                currentTransition = transition;
                dBufferRequired = RequiresDBuffer(transition);
                transitionFunc = GetTransitionFunc(transition);
                //   transitionControl.OnLeave(this.Host);
                transitionControl = Pages[name];
                //      transitionControl.OnEnter(this.Host);
                Animation animation = EnsureAnimation();

                animation.BeginValue = 0;
                animation.EndValue = Width;
                animation.Duration = duration;
                OnBeginTransition(name);
                animation.Start();
            }

        }

        private ChangedEventArgs<string> beginTransitionEventArgs = new ChangedEventArgs<string>();

        private void OnBeginTransition(string index)
        {
            if (BeginTransition != null)
            {
                beginTransitionEventArgs.NewValue = index;
                BeginTransition(this, beginTransitionEventArgs);
            }

        }

        public event EventHandler<ChangedEventArgs<string>> BeginTransition;

        private void StopTransition()
        {
            Animation animation = EnsureAnimation();
            animation.Wait();
            //animation.Stop();
            currentTransition = Transition.None;
            dBufferRequired = false;
        }

        #endregion

        public override bool IsDoubleBuffered
        {
            get { return IsInTransiton ? false : SelectedPage != null ? SelectedPage.IsDoubleBuffered : false; }
        }
        //private static PageManagerDic instance;
        //public static PageManagerDic Instance
        //{
        //    get
        //    {
        //        if (instance == null)
        //        {
        //            instance = new PageManagerDic();
        //        }
        //        return instance;
        //    }
        //    set
        //    {
        //        instance = value;
        //    }

        //}

    }
}
